package com.mzm.ui;

import java.awt.HeadlessException;
import java.awt.event.ActionEvent;
import java.util.LinkedHashMap;
import java.util.Map;

import javax.swing.Action;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;

import org.apache.commons.lang.exception.ExceptionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.mzm.remoting.DelegatedMzmServices;
import com.mzm.remoting.ExceptionListener;
import com.mzm.remoting.IMzmServices;
import com.mzm.remoting.MzmServices;

import dnl.confij.apps.ApplicationConfiguration;
import dnl.util.ui.ErrorDialog;
import dnl.util.ui.GridDialog;
import dnl.util.ui.ProgressDialog;
import dnl.util.ui.WindowUtils;
import dnl.util.ui.actions.AbstractAction;

@SuppressWarnings("serial")
public abstract class BaseApp extends JFrame {

	protected final Logger logger;
	
	private DelegatedMzmServices delegatedServices = new DelegatedMzmServices();

	private JMenuBar menuBar = new JMenuBar();

	private Map<String, JMenu> menus = new LinkedHashMap<String, JMenu>();

	private ApplicationConfiguration application;
	
	public BaseApp(String title) throws HeadlessException {
		super(title);
		logger = LoggerFactory.getLogger("APP");
		application = new ApplicationConfiguration(title);
		initMenuBar();
		this.setJMenuBar(menuBar);
		delegatedServices.registerExceptionListener(new ExceptionListener() {
			@Override
			public void exceptionReported(Exception e) {
				ProgressDialog.finished(BaseApp.this);
				String message = e.getMessage();
				if(message.startsWith("Could not connect")){
					ErrorDialog.showDialog(BaseApp.this, "Error", "Could not connect", ExceptionUtils.getFullStackTrace(e));
				}
				else {
					ErrorDialog.showDialog(BaseApp.this, "Error", e);
				}
			}
		});
	}

	protected abstract void connected();

	protected IMzmServices getBizAppServices() {
		return delegatedServices;
	}
	

	public void saveConfigObject(String id, Object object) {
		application.saveConfigObject(id, object);
	}

	public Object getConfigObject(String id) {
		return application.getConfigObject(id);
	}

	private void initMenuBar() {
		addMenu("Connection");
		addMenuItem("Connection", new AbstractAction("Select Host") {
			@Override
			public void actionPerformedImpl(ActionEvent arg0) {
				SwingUtilities.invokeLater(new Runnable() {
					@Override
					public void run() {
						GridDialog gridDialog = new GridDialog(BaseApp.this, new String[] {
								"Host",
								"Port" }, new String[] { "localhost", "8080" });
						
						String lastHost = (String) getConfigObject("networking.lastHost");
						if(lastHost != null){
							gridDialog.setValue("Host", lastHost);
						}
						
						WindowUtils.centerWindowRelative(gridDialog, BaseApp.this);
						gridDialog.setVisible(true);
						if(gridDialog.wasCancelled())
							return;
						logger.info("Attempting to connect ...");
						ProgressDialog.showProgress(BaseApp.this, "Connecting ...", 10);
						String host = gridDialog.getValue("Host");
						saveConfigObject("networking.lastHost", host);
						String port = gridDialog.getValue("Port");
						IMzmServices services = MzmServices.getHttpInvokerServices(host
								+ ":" + port);
						ProgressDialog.showProgress(BaseApp.this, "Connecting ...", 50);
						delegatedServices.setDelegate(services);
						if(!handshakeWithServer()){
							JOptionPane.showMessageDialog(BaseApp.this, "Handshake with server failed");
						}
						connected();
						ProgressDialog.showProgress(BaseApp.this, "Connected ...", 100);
						logger.info("Connected");
					}
				});
			}
		});
	}

	private boolean handshakeWithServer() {
		// TODO: replace this slow call!
		//List<String> availableObjectTypes = delegatedServices.getEntityManagementFacade()
		//		.getAvailableObjectTypes();
		return true;
	}

	public void addMenu(String name) {
		JMenu menu = new JMenu(name);
		menus.put(name, menu);
		menuBar.add(menu);
	}

	public void addMenuItem(String menuName, Action action) {
		JMenuItem menuItem = new JMenuItem(action);
		JMenu menu = menus.get(menuName);
		menu.add(menuItem);
	}

}
